package com.t4.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.t4.auth.mapper.SysMenuMapper;
import com.t4.auth.mapper.SysRoleMapper;
import com.t4.auth.mapper.SysRoleMenuMapper;
import com.t4.auth.mapper.SysUserRoleMapper;
import com.t4.auth.service.SysMenuService;
import com.t4.auth.utils.MenuHelper;
import com.t4.common.exception.T4Exception;
import com.t4.model.system.SysMenu;
import com.t4.model.system.SysRoleMenu;
import com.t4.model.system.SysUserRole;
import com.t4.vo.system.AssignMenuVo;
import com.t4.vo.system.RouterVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {


    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;



    /**
     * 对于有层级关系的树形结构，这里采用递归来解决
     * 1. 找到所有菜单的根节点，即parentId=0的节点
     * 2. 遍历每个根节点，对每个根节点遍历到最底层的节点，然后返回次层节点遍历到最底层节点...直到递归回来
     * @return
     */
    @Override
    public List<SysMenu> findNodes() {
        // 获取所有菜单节点
        List<SysMenu> sysMenuList = this.list();
        if(CollectionUtils.isEmpty(sysMenuList)){
            return null;
        }

        // 构建树型结构
        List<SysMenu> result = MenuHelper.builderTree(sysMenuList);

        return result;
    }

    @Transactional
    @Override
    public void doAssign(AssignMenuVo assignMenuVo) {
        Long roleId = assignMenuVo.getRoleId();
        // 1. 删除原有角色的权限
        sysRoleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>()
                .eq(SysRoleMenu::getRoleId, roleId));

        // 2. 给角色新增权限
        List<Long> menuIdList = assignMenuVo.getMenuIdList();
        menuIdList.forEach(i -> {
            if(!StringUtils.isEmpty(i)) {
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setRoleId(roleId);
                sysRoleMenu.setMenuId(i);
                sysRoleMenuMapper.insert(sysRoleMenu);
            }
        });
    }

    @Override
    public List<SysMenu> toAssign(Long roleId) {
        // 1. 获取全部菜单列表
        List<SysMenu> allSysMenuList = this.list(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getStatus, 1));

        // 2. 根据角色id获取角色权限id
        List<SysRoleMenu> sysRoleMenuList = sysRoleMenuMapper.selectList(new LambdaQueryWrapper<SysRoleMenu>()
                .eq(SysRoleMenu::getRoleId, roleId));
        List<Long> menuIdList = sysRoleMenuList.stream().map(e -> e.getMenuId()).collect(Collectors.toList());

        // 3. 根绝角色权限id，获取角色权限对象
        allSysMenuList.forEach(i -> {
            if(menuIdList.contains(i.getId())){
                i.setSelect(true);
            }else {
                i.setSelect(false);
            }
        });
        // 4. 创建树型结构返回
        return MenuHelper.builderTree(allSysMenuList);
    }

    @Override
    public List<RouterVo> findUserMenuListByUserId(Long userId) {
        List<SysMenu> sysMenuList = null;
        // 1. 判断当前用户是否实管理员（约定userId=1为管理员）
        // 1.1 是，查询所有菜单列表（使用中的）
        if(userId.longValue() == 1) {
            sysMenuList = baseMapper.selectList(new LambdaQueryWrapper<SysMenu>()
                    .eq(SysMenu::getStatus, 1).orderByAsc(SysMenu::getSortValue));
        }else {
            // 1.2 不是，根绝userId查询可以操作的菜单列表
            //     多表关联查询：用户角色关系表、角色菜单关系表、菜单关系表
            sysMenuList = baseMapper.findMenuListByUserId(userId);
        }
        // 2. 把查询出来的数据列表构建成要求的路由结构
        // 2.1 将数据列表构建成树型结构
        List<SysMenu> sysMenuTreeList = MenuHelper.builderTree(sysMenuList);
        // 2.2 将树型结构改造成要求的路由结构
        List<RouterVo> routerList = MenuHelper.buildRouter(sysMenuTreeList);
        return routerList;
    }

    @Override
    public List<String> findUserPermsByUserId(Long userId) {
        List<SysMenu> sysMenuList = null;
        // 1. 判断当前用户是否实管理员（约定userId=1为管理员）
        // 1.1 是，查询所有菜单列表（使用中的）
        if(userId.longValue() == 1) {
            sysMenuList = baseMapper.selectList(new LambdaQueryWrapper<SysMenu>()
                    .eq(SysMenu::getStatus, 1));
        }else {
            // 1.2 不是，根绝userId查询可以操作的菜单列表
            //     多表关联查询：用户角色关系表、角色菜单关系表、菜单关系表
            sysMenuList = baseMapper.findMenuListByUserId(userId);
        }
        // 2. 把查询出来的数据列表构建成要求的结构
        List<String> permList = sysMenuList.stream()
                .filter(i -> i.getType() == 2)
                .map(i -> i.getPerms())
                .collect(Collectors.toList());
        return permList;
    }


    /**
     * 能够删除菜单的条件为：没有子节菜单
     * 方式：从所有菜单中找到parentId满足条件的，如果有，则不能删除
     * @param id
     * @return
     */
    @Override
    public boolean removeById(Serializable id) {
        // 父节点Id = id 的个数
        int count = this.count(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getParentId, id));
        if(count > 0){
            throw new T4Exception(201, "菜单不能删除");
        }
        return super.removeById(id);
    }
}
